package com.esdk.utils;

import com.esdk.exception.SdkRuntimeException;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 用于对User::getId进行解析，获取类和方法名
 */
public interface MethodReference<T,R> extends Serializable{

  R invoke(T t);

  class Helper{
    private static final ConcurrentHashMap<Class<? extends MethodReference>, Signature> CACHE = new ConcurrentHashMap<>();
  }

  default String getTargetMethodName(){
    return getSignature().methodName;
  }

  default Class<T> getTargetClass(){
    return (Class<T>)getSignature().clazz;
  }

  private Signature getSignature(){
    return Helper.CACHE.computeIfAbsent(this.getClass(), (clazz) -> {
      try {
        Method writeReplace = clazz.getDeclaredMethod("writeReplace");
        writeReplace.setAccessible(true);
        SerializedLambda lambdaInfo = (SerializedLambda)writeReplace.invoke(MethodReference.this);
        String methodDescriptor = lambdaInfo.getInstantiatedMethodType();
        int start = methodDescriptor.indexOf('L') + 1;
        int end = methodDescriptor.indexOf(';', start);
        return new Signature(methodDescriptor.substring(start, end).replace("/", "."), lambdaInfo.getImplMethodName());
      } catch (NoSuchMethodException|InvocationTargetException|IllegalAccessException|ClassNotFoundException e) {
        throw new SdkRuntimeException("lambda getter获取失败", e);
      }
    });
  }

  class Signature{
    private String methodName;
    private Class<?> clazz;
    private Signature(String className, String methodName) throws ClassNotFoundException {
      this.clazz = Class.forName(className);
      this.methodName = methodName;
    }
  }

}
